;;########################################################################
;; dashobj1.lsp
;; Contains data and datasheet menu functions NEW-DATA and OPEN-DATA
;; and datasheet constructor function DATASHEET
;; Copyright (c) 1994-2002 by Forrest W. Young
;;########################################################################
;; changed fwy 03-16-03

;;--------------------
;; data menu functions
;;--------------------


(defun new-data (&optional (new-data-type nil) initial (show-datasheet t)
                           (size '(500 250)) (location nil) (shrink-wrap nil) (info t))
"Args: &optional size '(500 250) location shrink-wrap (info t)
Creates new data object of type new-data-type and an associated new datasheet. Returns data id."
  (if (or (not *vista-exists*) initial)
      (initial-new-data new-data-type initial show-datasheet)
      (enter-data :size size :location location :shrink-wrap shrink-wrap :info info)))

(defun initial-new-data (&optional (new-data-type nil) initial (show-datasheet t)) ;"New"
"Args: &optional new-data-type initial
Creates new data object of type new-data-type and an associated new datasheet. The variable NEW-DATA-TYPE must be a string which is one of \"MV\", \"Cat\", \"Class\", \"FreqClass\", \"Freq\", \"Mat\", \"Missing\", \"Hidden\" or \"New\". New by default. Hidden is MV without icon. INITIAL is true if the datasheet for these data will be the first datasheet. Returns data id."
  (let* ((return2 t)
         (return)
         (dash)
         (choice nil))
    (cond
      (new-data-type
       (setf return
             (cond 
               ((equal (string-downcase new-data-type) "hidden")  (list "NewData" 7))
               ((equal (string-downcase new-data-type) "missing") 
                (list (get-string-dialog "Name of the New DataSheet" :initial "NewData") 5))
               ((equal (string-downcase new-data-type) "new")  (list "Unnamed" 8))
               ((equal (string-downcase new-data-type) "mv")   (list "Multivariate" 0))
               ((equal (string-downcase new-data-type) "freq") (list "FreqTable" 1))
               ((equal (string-downcase new-data-type) "mat")  (list "Matrix"    2)))))
      (t
       (setf return (new-data-dialog))))
    (when return
          (setf choice (second return))
          (case choice 
            (5 (setf dob
                (data (first return) 
                      :data-type "missing" :array nil :freq nil :show-icon nil
                      :variables '("Var1") :labels '("Obs1" "Obs2") 
                      :data '("---" "---") :new-data t :watcher nil)))
            (6 (send *help-window* :show-window))
            (8 (setf dob
                (data "NewData"  
                      :iconify "datasheet" 
                      :known-as "NewData" 
                      :buffer t
                      :data-type "new" 
                      :array nil :freq nil :show-icon nil
                      :variables '("Var1") :labels '("Obs1" "Obs2") 
                      :data '("---" "---") :new-data t :watcher nil)))
            (7 (setf dob
                (data "Hidden" :iconify nil
                      :data-type "new" :array nil :freq nil :show-icon nil
                      :variables '("Var1") :labels '("Obs1" "Obs2")
                      :data '("---" "---") :new-data t :watcher nil)))
            (0 (setf dob
                (data (first return) :show-icon nil
                      :data-type "multivariate" :array nil :freq nil
                      :variables '("Var1") :labels '("Obs1" "Obs2") 
                      :data '("---" "---") :new-data t :watcher nil)))
            (2 (setf dob
                (data (first return)
                      :data-type "matrix" :array nil :freq nil :show-icon nil
                      :variables '("RowCol1" "RowCol2")  
                      :data '("---" "---" "---" "---")
                      :shapes '("Symmetric") :watcher nil
                      :matrices '("Mat1") :new-data t)))
            (1 (let* ((title (send text-item-proto :new 
                                   (format nil "Row and Column Labels - Leave one~%label blank for one-way data:")))
                      (rowtxt (send text-item-proto :new "Row Label:"))
                      (coltxt (send text-item-proto :new "Column Label:"))
                      (rowname (send edit-text-item-proto :new "Row" 
                                     :text-length 14))
                      (colname (send edit-text-item-proto :new "Column" 
                                     :text-length 14))
                      (colstring "Col")
                      (OK   (send modal-button-proto :new "OK" 
                              :action #'(lambda ()                              
                               (list (send rowname :text) (send colname :text)))))
                      (cancel (send modal-button-proto :new "Cancel"))
                      (dialog (send modal-dialog-proto :new
                                   (list title 
                                         (list (list rowtxt coltxt)
                                               (list rowname colname))
                                         (list OK cancel))
                                   :default-button OK)))
                 (setf return2 (send dialog :modal-dialog))
                 (when return2
                       (let* ((row-label (first return2))
                              (col-label (second return2))
                              (nrows (if (> (length row-label) 0) 2 1))
                              (ncols (if (> (length col-label) 0) 2 1))
                              (colstring (if (equal col-label "Columns") 
                                             "Col" col-label))
                              (var-names (list (strcat colstring "1")
                                               (strcat colstring "2")))
                              (obs-names (list (strcat row-label "1")
                                               (strcat row-label "2")))
                              (ndata (* nrows ncols))
                              (vars (if (= 2 ncols) var-names (list (first var-names)))) 
                              (rows (if (= 2 nrows) obs-names (list (first obs-names))))
                              )
                         (setf dob 
                          (data (first return)
                                :data-type "freq" :array t :freq t
                                :variables vars :labels rows 
                                :data (repeat 0 ndata) :show-icon nil
                                :row-label row-label :watcher nil
                                :column-label col-label :new-data t))
                         )))))
          
          (set-current-data-variables dob);fwy 102199
         ; (when initial (show-datasheet dob :new-data t :show t :initial initial))
         (when show-datasheet
               (setf dash (datasheet dob :new-data t :editable t :initial initial))
               (unless initial (send dash :pop-me-out)))
          (if dash dash data)
          )))


(defun make-new-data (return)
  (let* ((name (first return))
         (type (second return))
         (dob)
         )
    (case type
      (2 (setf dob
               (data name 
                     :data-type "new" 
                     :iconify nil 
                     :variables '("Var1" )
                     :labels '("Obs1" "Obs2")
                     :types '("Category" )
                     :data '("---" "---"))))
      (1 (setf dob
                (data name
                      :data-type "matrix" 
                      :iconify nil
                      :array nil 
                      :freq nil 
                   ;   :show-icon nil 
                   ;   :new-data t
                      :variables '("RowCol1" "RowCol2")
                      :labels    '("RowCol1" "RowCol2")
                      :data      '("---" "---" "---" "---")
                      :shapes    '("Symmetric") :watcher nil
                      :matrices  '("Mat1") )))
      (0 (let* ((title (send text-item-proto :new 
                             (format nil "Row and Column Labels - Leave one~%label blank for one-way data:")))
                (rowtxt (send text-item-proto :new "Row Label:"))
                (coltxt (send text-item-proto :new "Column Label:"))
                (rowname (send edit-text-item-proto :new "Row" 
                               :text-length 14))
                (colname (send edit-text-item-proto :new "Column" 
                               :text-length 14))
                (colstring "Col")
                (OK   (send modal-button-proto :new "OK" 
                            :action #'(lambda ()                              
                                        (list (send rowname :text) (send colname :text)))))
                (cancel (send modal-button-proto :new "Cancel"))
                (dialog (send modal-dialog-proto :new
                              (list title 
                                    (list (list rowtxt coltxt)
                                          (list rowname colname))
                                    (list OK cancel))
                              :default-button OK)))
           (setf return2 (send dialog :modal-dialog))
           (when return2
                 (let* ((row-label (first return2))
                        (col-label (second return2))
                        (nrows (if (> (length row-label) 0) 2 1))
                        (ncols (if (> (length col-label) 0) 2 1))
                        (colstring (if (equal col-label "Columns") 
                                       "Col" col-label))
                        (var-names (list (strcat colstring "1")
                                         (strcat colstring "2")))
                        (obs-names (list (strcat row-label "1")
                                         (strcat row-label "2")))
                        (ndata (* nrows ncols))
                        (vars (if (= 2 ncols) var-names (list (first var-names)))) 
                        (rows (if (= 2 nrows) obs-names (list (first obs-names))))
                        )
                   (setf dob 
                         (data name
                               :data-type "freq" 
                               :array t :freq t
                               :variables vars :labels rows 
                               :data (repeat 0 ndata)
                               :iconify nil 
                              ; :show-icon nil
                              ; :new-data t
                               :row-label row-label :watcher nil
                               :column-label col-label ))
                   )))))
    dob))



(defun open-data (&optional file (path *current-data-dir-name*) keep-old-data-path?)
"Args: (&optional file path keep-old-data-path?)
Manages the opening of datafile FILE. If the optional string argument FILE is included, the data object is loaded from FILE, otherwise a dialog is presented to select the file. The string need not end with .lsp. The dialog opens at PATH, which defaults to *current-data-dir-name*.   Returns the object-id of the data object. Note: Load-Data opens the file. Data creates the data object. SetCD makes the new data object current. Browse-Data prepares the datasheet. Datasheet creates and displays the datasheet."
  (when *watcher*
        (when (send *watcher* :showing)
              (send *watcher* :write-text "Opening Data File" :show t)))
  (let ((result  (load-data file path keep-old-data-path?)))
    (when result 
          (when *watcher*
                (when (send *watcher* :showing)
                      (send *watcher* :write-text "Constructing Datasheet" :show t)))
          (when *needs-desktop-resized* 
                (save-desktop-settings)
                (setf *needs-desktop-resized* nil))
          (when (send *vista* :guidemap) (send *guidemap* :gui t))
          (when (send *current-data* :missing-values)
                (help "\nMISSING VALUES:\nThese data have missing values (coded as NIL). Before analyzing them you must use the DATA menu's IMPUTE MISSING VALUES menu item.")))
    (when *watcher* (send *watcher* :hide-window))
    (when *show-datasheet-after-loading-data* (edit-data));fwy changed 09-18-02 to (edit-data)
                                                            ;fwy changed 03-01-03 to (browse-data)
    result))


;;--------------------
;; constructor function
;;--------------------

(defun datasheet (&optional data-object 
                  &key      editable (in *desktop-container* inset) 
                            (name nil name?) (names nil)
                            (button-bar nil) menu-bar (show-info nil)
                            window title size location frame-location toolwindow
                            initial ncolumns ndecimals (show t) dont-adjust-sizeloc
                            shrink-wrap new-data (container *desktop-container* cont?) 
                            supervisor)
"Args: DATA-OBJECT &KEY EDITABLE (IN *DESKTOP-CONTAINER*) (KNOWN-AS) NEW-DATA INITIAL NCOLUMNS NDECIMALS WINDOW SHRINK-WRAP DONT-ADJUST-SIZELOC TITLE SIZE LOCATION FRAME-LOCATION TOOLWINDOW (SHOW T) CONTAINER 
Constructor function for constructing datasheet for editing or browsing DATA-OBJECT. Datasheet will be named  unless name is not specified, in which case the name will be KNOWN-AS, unless it is nil, in which case the name is constructed from the name of the data object. Will be EDITABLE if T with fields NCOLUMNS in width and displaying numeric values with NDECIMALS precision. Datasheet shown in new window unless WINDOW specifies an existing window object, and shown in *desktop-container* unless CONTAINER specifies another container. Shrink-wraps window arround datasheet when SHRINK-WRAP is t. from-data-constructor deals with special cases whenthe datasheet is being invoked from the data constructor function"
  ;(print (list "dashobj1.lsp datasheet names=" names))
  (when *watcher*
        (when (send *watcher* :showing)
              (send *watcher* :write-text "Making Datasheet" :show t)))
  (unless inset (setf in container)
          (setf inset cont?))
  (let* ((in? inset)
         ;fwy replaced next several lines with 5 follow below 3-16-03
         ;(datatype-name (generalized-datatype 
         ;               (send data-object :active-types '(all)) 
         ;               (send data-object :freq-data?)
         ;               (send data-object :new-data?)
         ;               nil ;(send data-object  :missing-data?)
         ;               (send data-object  :matrix-data?)))
         ;(datatype-ext (second datatype-name))
         ;(datatype-name (first datatype-name))
         ;(datatype (data-type-abbreviation datatype-name))
         ;(datatype-string (if (send data-object :freq)                    ;fwy 12182000
         ;                     (if (equal datatype "Frqncy")
         ;                         (format nil "Type:Freq")
         ;                         (format nil "Type:Freq-~a "datatype))
         ;                     (format nil "Type:~a "datatype)))
         ;(datatype-name 
         ;  (if (equal datatype-name "crosstabs") "General" datatype-name))
	 ;fwy added next 5 lines 3-16-03
         (datatype-names-list (datatype? data-object))
	 (datatype-name   (first datatype-names-list))
	 (datatype-string (strcat "DataType:" (second datatype-names-list)))
         (datatype        (second datatype-names-list))
	 (datatype-ext    (third datatype-names-list))
         (dash-title (if title title 
                         (format nil "~a (DataSheet ~a)" 
                                 (send data-object :name) 
                                 (if editable "Editor" "Browser"))))
         (dash-size (if size size
                        (- (send *vista* :datasheet-sizes) (list 2 56))));6 60
         (datasize-string (format nil "Size:~d X ~d " 
                                  (send data-object :nobs) (send data-object :nvar)))
         (curcon *active-container*)
        
         (actcon 
           (if (and in? (not in))
               (container :title "DataSheet Container" :localmenu t :show nil :in nil)
               (container :title "DataSheet Container" :localmenu t :show nil)))
         (object
           (cond
             (window (if window window actcon))
             ((and in? (not in))
              (enable-container actcon)
              ;(ADD-MENUBAR ACTCON)
              (send datasheet-proto :new 2 :size dash-size :show nil :toolwindow toolwindow))
             (t
              (enable-container in)
              ;(ADD-MENUBAR ACTCON)
              (send datasheet-proto :new 2 :size dash-size :show nil))))
       ;  (enable-container object)
	(add-menubar object)
       ;  (prt (defmeth object :print (&optional arg) (call-next-method)))
       ;  (prt (defmeth datasheet-proto :print (&optional arg) (call-next-method)))
         (JUNK (WHEN *VERBOSE* 
                     (PRINT (LIST "DASHOBJ2.LSP: DATASHEET" OBJECT))
                     (PRINT (LIST "DASHOBJ2.LSP: CONTAINER" ACTCON))))
#+containers(junk (when *ni* (enable-container curcon)))
#+msdos  (loc (+ (list 35 90) (send *workmap* :location)))
#-msdos  (loc (+ (list 30 105) (send *workmap* :location)))
         (loc (if (or frame-location location)
                  (if location location frame-location)
                  (list (first (send *workmap* :location))
                    (second (+ 28 (send *workmap* :location) 
                               (send *workmap* :size))))))
         (nvar   (send data-object :nvar))
         (nobs   (send data-object :nobs))
         
         (tw     (send object :text-width "9"))
         (data   (cond
                   ((send data-object :matrices)
                    (send data-object :data))
                   ((send data-object :ways)
                    (combine (send data-object :data)))
                   (t
                    (send data-object :active-data '(numeric ordinal))))) 
         (nonil  (remove nil (remove "NIL" data :test #'equal) :test #'equal))
         (nonil  (remove nil (remove " "   data :test #'equal) :test #'equal))
         (nonil t)
         (ndigit 6)
         (dsobj-args (send data-object :datasheet-arguments))
         (ndciml (if dsobj-args (third dsobj-args) 2))
         (ndciml (if (send data-object :freq) 0 ndciml))
         (ndciml (if ndecimals ndecimals ndciml))	
         (ncols  (max 8 (+ ndigit ndciml)))
         (ncols  (if dsobj-args (fourth dsobj-args) ncols))
         (ncols  (if ncolumns ncolumns ncols))
         (dcimlw (send object :text-width "."))
         (signw  (send object :text-width "-"))
         (fw     (+ (* tw ncols) dcimlw signw 6))
         (fh     (+ (send object :text-ascent) 
                    (send object :text-descent) 3)) 
         (lw     nil)
         (cw (max (send object :text-width datatype-string)
                  (send object :text-width datasize-string)))
         (x+ 0)
         (y+ 0);(y+ 18)
         (extension) (full-name)
         (tmpname)
         ) 
    (setf name (if name? name (strcat (if editable "Ed!" "Br!")
                                     (send data-object :name))))
    (send object :container (if (and in? (not in)) actcon in))
    (when (send object :menu) 
          (send (send object :menu) :remove)
          (send object :menu nil))
    (send object :data-type datatype)
    (send object :datatype-string datatype-string)
    (send object :datasize-string datasize-string)
    (send object :edited (send data-object :edited))
    (if editable (send object :editable editable)
        (send object :editable (send data-object :editable)))
    (send object :redraw-overlays)
    (send object :hot-cell nil)
    (setf tmpname name)
    (cond
      (names
       (setf name (first names))
       (setf full-name (second names))
       (setf proper-name (third names))
       (setf elipsis-name (fourth names))
       (setf nickname (fifth names))
       (setf extension (sixth names))
       )
      (t
       (setf name (get-sob-extension  name))
       (setf extension (third name))
       (setf full-name (first name))
       (setf name (if name?  tmpname (second name)))
       (setf proper-name (proper-name (first (parse-name full-name)) "dsh" ))
       (setf elipsis-name (elipsis-name proper-name))
       ))
    (send object :name name)
    (send object :full-name full-name)
    (send object :extension extension)
    (send object :proper-name proper-name)
    (send object :elipsis-name elipsis-name)
    (set (intern (string-upcase (send object :full-name))) object)
    (set (intern (string-upcase (send object :proper-name))) object)
    (set (intern (string-upcase (send object :name))) object)
    (when *watcher*
        (when (send *watcher* :showing)
              (send *watcher* :write-text "Preparing Datasheet" :show t)))
    (cond
      ((or menu-bar button-bar) 
       (send object :margin 0 (+ 317 (send object :text-descent)) 0 0))
      (t (send object :margin 0 0 0 0)))
    (send object :initial initial)
    (send object :title dash-title)
    (send object :x+ x+)
    (send object :y+ y+)
    (send object :use-color t)
    (send object :nvar nvar)
    (when (send data-object :matrices)
          (send object :nmat (send data-object :nmat)))
    (send object :variable-strings 
          (copy-list (send data-object :variables)))
    (send object :matrix-strings 
          (copy-list (send data-object :matrices)))
    (send object :type-strings (copy-list (send data-object :types))) 
    (send object :create-label-strings data-object)
    (setf fw (+ (* tw ncols) dcimlw signw 6))
    (setf lw (max (* 10 tw) 
                  fw 
                  cw
                  (+ 6 (max (map-elements #'send object :text-width 
                                          (send object :label-strings))))))
    (send object :field-width  fw) 
    (send object :field-height fh)
    (send object :label-width  lw)
   ;(send object :corner-width cw);fwy changed 11022000 -
    (send object :corner-width lw);label and corner width must be the same
    (when dsobj-args
          (if (some #'< (- screen-size 
                           (+ (first dsobj-args) (second dsobj-args)))
                    (list 0 0))
              (setf dsobj-args nil)))
    (apply #'send object :location loc);new
    (send object :data-object data-object)
    (send object :nobs nobs) 
    (send object :newvar 0)
    (send object :newobs 0)
    (send object :newmat 0)
    (send object :number-of-decimals ndciml)
    (send object :number-of-columns ncols)
    (send object :create-data-matrix-strings)
    (send object :editable editable)
    
    (unless window (if editable
                       (send object :editor-buttons)
                       (send object :browser-buttons)))
    (send object :redraw-now t)
    (unless window (send data-object :datasheet-object object))
    (when *watcher*
          (when (send *watcher* :showing)
                (send *watcher* :write-text "Showing Datasheet" :show t)))
    (when (and (send data-object :iconify) (not supervisor))
          (setcds object)
          ;(when *current-datasheet*
          ;      (setf *previous-datasheet* *current-datasheet*))
          ;(setf *current-datasheet* object)]
          (setf *datasheet* object))
    (when *fake-datasheet* 
          (send *fake-datasheet* :remove)
          (setf *fake-datasheet* nil)
          (when *ENABLE-SCREEN-SAVER-FEATURE*
                (send command-menu-show-screen-saver-item :enabled t)
                (send command-menu-screen-saver-options-item :enabled t)))
    (when (and (send *vista* :screen-saver-on) 
               *ENABLE-SCREEN-SAVER-FEATURE*)
          (send object :idle-on t)
          (send *workmap*  :reset-screen-saver))
    (send object :set-scroll-bars fw fh lw nvar nobs);blink
    (send object :h-scroll-incs fw (* 4 fw))
    (send object :v-scroll-incs fh (* 10 fh))
    
    (when (and show (not dont-adjust-sizeloc)) 
;appears first time with next statement
          (when (not *free-about-window*)
                (send *vista* :adjust-about-sizeloc))) 
    (if shrink-wrap 
	(send object :shrink-wrap? t)
	(send object :shrink-wrap))
    (when (send object :needs-revealing)
          (send object :reveal))
    (when *watcher*
          (when (send *watcher* :showing)
                (send *watcher* :write-text "  " :show t)))
    (when *verbose* (Print "Datasheet Constructed: Whew"))
    (send object :top-most nil)
    (send object :bottom-most nil)
    (send object :elapsed-time
              (/ (- (get-internal-real-time) (send object :statobj-start-time))
                 internal-time-units-per-second))
    (send object :instance-info
          (format nil ";         Instantiated: ~a; Elapsed: ~,3d Seconds;" 
                    (select (date-time) 9)
                    (fuzz (send object :elapsed-time) 3)))
    (when show-info (send object :info))
    (send object :define-dash-vartype-menu)
    (defmeth object :do-click (x y m1 m2)
       (call-next-method x y m1 m2))
    object)) 



;;-------------------------
;; datasheet menu functions
;;-------------------------
   


(setf *watcher* nil)

(defun new-data-dialog ()
  (flet ((suggested-name (name case) 
            
            (send name :text
                  (case (send case :value)
                            (0 "NewFreqTable") (1 "NewMatrixData") (2 "NewData") ) ))
         )
    (let* ((txt1 (send text-item-proto :new "Which Kind of Data?"))
           (name (send edit-text-item-proto :new "NewData" :text-length 21))
           (txt2 (send text-item-proto :new "The New Data Will Be Named:"))
           (type (send choice-item-proto :new
                       '( "Frequency Table Data" 
                          "Matrix Data"
                          "All Other Types" 
                          )
                       :value 2))
           (dummy (defmeth type :do-action ()
                    (suggested-name name type)))
           (HELP (send modal-button-proto :new "Help" 
                       :action #'(lambda ()
                                   (new-data-help)
                                   nil))) ;(list (send name :text) 6)
           (OK   (send modal-button-proto :new "OK" 
                       :action #'(lambda () 
                                   (list (send name :text) (send type :value)))))
           (cancel (send modal-button-proto :new "Cancel"))
           (dialog (send modal-dialog-proto :new
                         (list (list (list txt1 type ) 
                                     (list txt2 name (list OK cancel) HELP))) 
                         :default-button OK))
           (return2 t)
           (return (send dialog :modal-dialog))
           (choice nil) 
           )
      return)))


(defun new-datasheet (&optional (data-type "missing"))
"Arg: &optional data-type
Creates new data object of type new-data-type and an associated new datasheet. The variable NEW-DATA-TYPE must be a string which is one of \"MV\", \"Cat\", \"Class\", \"FreqClass\", \"Freq\", \"Mat\", \"Missing\", \"Hidden\" or \"New\". New by default. Hidden is MV without icon.  Returns datasheet id."
  (enter-data data-type))

(defun new-data-help ()
  (send *workmap* :show-help new-data-file-menu-item))


             
(defun new-observation ()
  (send *datasheet* :expand-mv-datasheet nil t 1))


(defun new-observations (&optional (n 0))
  (when (= n 0) 
        (send *datasheet* :redraw-now nil)
        (setf n (first (get-value-dialog 
                        "Number of New Observations" :initial 1))))
  (cond 
    (n 
     (when (< n 1) (error "You Must Add at Least 1 New Observation."))
     (send *datasheet* :expand-mv-datasheet nil t n))
    (t
     (send *datasheet* :redraw-now t)
     (send *datasheet* :redraw))))

(defun new-variable ()
  (send *datasheet* :expand-mv-datasheet t nil 1))

(defun new-variables (&optional (n 0))
  (when (= n 0) 
        (send *datasheet* :redraw-now nil)
        (setf n (first (get-value-dialog 
                        "Number of New Variables" :initial 1)))
        )
  (cond 
    (n
     (when (< n 1) (error "You Must Add at Least 1 New Variable."))
     (send *datasheet* :expand-mv-datasheet t nil n))
    (t
     (send *datasheet* :redraw-now t)
     (send *datasheet* :redraw))))


(defun new-row-and-column ()
  (send *datasheet* :expand-mat-datasheet t nil 1))

(defun new-rows-and-columns (&optional (n 0))
  (when (= n 0) 
        (send *datasheet* :redraw-now nil)
        (setf n (first (get-value-dialog 
                        "Number of New Rows and Columns" :initial 1))))
  (when n 
        (when (< n 1) (error "You Must Add at Least 1 New Row and Column."))
        (send *datasheet* :expand-mat-datasheet t nil n)))

(defun new-matrix ()
  (send *datasheet* :expand-mat-datasheet nil t 1))

(defun new-matrices (&optional (n 0))
  (when (= n 0) 
        (send *datasheet* :redraw-now nil)
        (setf n (first (get-value-dialog 
                        "Number of New Matrices" :initial 1))))
  (when n 
        (when (< n 1) (error "You Must Add at Least 1 New Matrix."))
        (send *datasheet* :expand-mat-datasheet nil t n)))


       
       